package com.base.core.network.http.support;

import com.base.core.lang.StringUtils;
import com.base.core.network.http.Http;
import com.base.core.network.http.HttpHeader;
import com.base.core.constant.HttpConstants;
import com.base.core.exception.SimpleHttpException;
import com.base.core.network.http.ResponseEntity;
import com.base.core.utils.MapUtils;
import org.apache.http.Header;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * HttpClient 实现
 * </p>
 *
 * @author becker
 * @date Created in 2019/12/25 09:24
 */
public class HttpClient implements Http {
    private final CloseableHttpClient httpClient;

    public HttpClient() {
        this(HttpClients.createDefault());
    }

    public HttpClient(CloseableHttpClient httpClient) {
        this.httpClient = httpClient;
    }

    private ResponseEntity exec(HttpRequestBase request) {
        this.addHeader(request);
        // 设置超时时长
        request.setConfig(RequestConfig.custom().setConnectTimeout(HttpConstants.TIMEOUT).
                setSocketTimeout(HttpConstants.TIMEOUT).setConnectionRequestTimeout(HttpConstants.TIMEOUT).build());

        try (CloseableHttpResponse response = this.httpClient.execute(request)) {
            if (!isSuccess(response)) {
                throw new SimpleHttpException("Unexpected code " + response);
            }

            StringBuffer body = new StringBuffer();
            if (response.getEntity() != null) {
                body.append(EntityUtils.toString(response.getEntity(), HttpConstants.DEFAULT_ENCODING));
            }
            ResponseEntity responseEntity = new ResponseEntity();
            responseEntity.setCode(response.getStatusLine().getStatusCode());
            responseEntity.setMessage(response.getStatusLine().getReasonPhrase());
            responseEntity.setBody(body.toString());
            return responseEntity;
        } catch (IOException e) {
            throw new SimpleHttpException(e);
        }
    }

    /**
     * 添加request header
     *
     * @param request HttpRequestBase
     */
    private void addHeader(HttpRequestBase request) {
        String ua = HttpConstants.USER_AGENT;
        Header[] headers = request.getHeaders(ua);
        if (null == headers || headers.length == 0) {
            request.addHeader(ua, HttpConstants.USER_AGENT_DATA);
        }
    }

    private boolean isSuccess(CloseableHttpResponse response) {
        if (response == null) {
            return false;
        }
        if (response.getStatusLine() == null) {
            return false;
        }
        return response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300;
    }

    /**
     * GET 请求
     *
     * @param url URL
     *
     * @return 结果
     */
    @Override
    public ResponseEntity get(String url) {
        return this.get(url, null, false);
    }

    /**
     * GET 请求
     *
     * @param url    URL
     * @param params 参数
     * @param encode 是否需要 url encode
     *
     * @return 结果
     */
    @Override
    public ResponseEntity get(String url, Map<String, String> params, boolean encode) {
        return this.get(url, params, null, encode);
    }

    /**
     * GET 请求
     *
     * @param url    URL
     * @param params 参数
     * @param header 请求头
     * @param encode 是否需要 url encode
     *
     * @return 结果
     */
    @Override
    public ResponseEntity get(String url, Map<String, String> params, HttpHeader header, boolean encode) {
        String baseUrl = StringUtils.appendIfNotContain(url, "?", "&");
        url = baseUrl + MapUtils.parseMapToString(params, encode);

        HttpGet httpGet = new HttpGet(url);

        if (header != null) {
            MapUtils.forEach(header.getHeaders(), httpGet::addHeader);
        }

        return exec(httpGet);
    }

    /**
     * POST 请求
     *
     * @param url URL
     *
     * @return 结果
     */
    @Override
    public ResponseEntity post(String url) {
        HttpPost httpPost = new HttpPost(url);
        return this.exec(httpPost);
    }

    /**
     * POST 请求
     *
     * @param url  URL
     * @param data JSON 参数
     *
     * @return 结果
     */
    @Override
    public ResponseEntity post(String url, String data) {
        return this.post(url, data, null);
    }

    /**
     * POST 请求
     *
     * @param url    URL
     * @param data   JSON 参数
     * @param header 请求头
     *
     * @return 结果
     */
    @Override
    public ResponseEntity post(String url, String data, HttpHeader header) {
        HttpPost httpPost = new HttpPost(url);

        if (StringUtils.isNotEmpty(data)) {
            StringEntity entity = new StringEntity(data, HttpConstants.DEFAULT_ENCODING);
            entity.setContentEncoding(HttpConstants.DEFAULT_ENCODING.displayName());
            entity.setContentType(HttpConstants.CONTENT_TYPE_JSON);
            httpPost.setEntity(entity);
        }

        if (header != null) {
            MapUtils.forEach(header.getHeaders(), httpPost::addHeader);
        }

        return this.exec(httpPost);
    }

    /**
     * POST 请求
     *
     * @param url    URL
     * @param params form 参数
     * @param encode 是否需要 url encode
     *
     * @return 结果
     */
    @Override
    public ResponseEntity post(String url, Map<String, String> params, boolean encode) {
        return this.post(url, params, null, encode);
    }

    /**
     * POST 请求
     *
     * @param url    URL
     * @param params form 参数
     * @param header 请求头
     * @param encode 是否需要 url encode
     *
     * @return 结果
     */
    @Override
    public ResponseEntity post(String url, Map<String, String> params, HttpHeader header, boolean encode) {
        HttpPost httpPost = new HttpPost(url);

        if (MapUtils.isNotEmpty(params)) {
            List<NameValuePair> form = new ArrayList<>();
            MapUtils.forEach(params, (k, v) -> form.add(new BasicNameValuePair(k, v)));
            httpPost.setEntity(new UrlEncodedFormEntity(form, HttpConstants.DEFAULT_ENCODING));
        }

        if (header != null) {
            MapUtils.forEach(header.getHeaders(), httpPost::addHeader);
        }

        return this.exec(httpPost);
    }
}
